/**
 * @license  Highcharts JS v7.0.2 (2019-01-17)
 * Highcharts variwide module
 *
 * (c) 2010-2019 Torstein Honsi
 *
 * License: www.highcharts.com/license
 */
'use strict';
(function (factory) {
	if (typeof module === 'object' && module.exports) {
		factory['default'] = factory;
		module.exports = factory;
	} else if (typeof define === 'function' && define.amd) {
		define(function () {
			return factory;
		});
	} else {
		factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
	}
}(function (Highcharts) {
	(function (H) {
		/* *
		 * Highcharts variwide module
		 *
		 * (c) 2010-2019 Torstein Honsi
		 *
		 * License: www.highcharts.com/license
		 */



		var addEvent = H.addEvent,
		    seriesType = H.seriesType,
		    seriesTypes = H.seriesTypes,
		    pick = H.pick;

		/**
		 * @private
		 * @class
		 * @name Highcharts.seriesTypes.variwide
		 *
		 * @augments Highcharts.Series
		 */
		seriesType('variwide', 'column'

		    /**
		 * A variwide chart (related to marimekko chart) is a column chart with a
		 * variable width expressing a third dimension.
		 *
		 * @sample {highcharts} highcharts/demo/variwide/
		 *         Variwide chart
		 * @sample {highcharts} highcharts/series-variwide/inverted/
		 *         Inverted variwide chart
		 * @sample {highcharts} highcharts/series-variwide/datetime/
		 *         Variwide columns on a datetime axis
		 *
		 * @extends      plotOptions.column
		 * @since        6.0.0
		 * @product      highcharts
		 * @excluding    boostThreshold, crisp, depth, edgeColor, edgeWidth,
		 *               groupZPadding
		 * @optionparent plotOptions.variwide
		 */
		    , {
		    /**
		     * In a variwide chart, the point padding is 0 in order to express the
		     * horizontal stacking of items.
		     */
		        pointPadding: 0,
		        /**
		     * In a variwide chart, the group padding is 0 in order to express the
		     * horizontal stacking of items.
		     */
		        groupPadding: 0
		    }, {
		        pointArrayMap: ['y', 'z'],
		        parallelArrays: ['x', 'y', 'z'],
		        processData: function (force) {
		            this.totalZ = 0;
		            this.relZ = [];
		            seriesTypes.column.prototype.processData.call(this, force);

		            (this.xAxis.reversed ?
		                this.zData.slice().reverse() :
		                this.zData).forEach(
		                function (z, i) {
		                    this.relZ[i] = this.totalZ;
		                    this.totalZ += z;
		                },
		                this
		            );

		            if (this.xAxis.categories) {
		                this.xAxis.variwide = true;
		                this.xAxis.zData = this.zData; // Used for label rank
		            }
		        },

		        /**
		     * Translate an x value inside a given category index into the distorted
		     * axis translation.
		     *
		     * @private
		     * @function Highcharts.Series#postTranslate
		     *
		     * @param {number} index
		     *        The category index
		     *
		     * @param {number} x
		     *        The X pixel position in undistorted axis pixels
		     *
		     * @return {number}
		     *         Distorted X position
		     */
		        postTranslate: function (index, x, point) {

		            var axis = this.xAxis,
		                relZ = this.relZ,
		                i = axis.reversed ? relZ.length - index : index,
		                goRight = axis.reversed ? -1 : 1,
		                len = axis.len,
		                totalZ = this.totalZ,
		                linearSlotLeft = i / relZ.length * len,
		                linearSlotRight = (i + goRight) / relZ.length * len,
		                slotLeft = (pick(relZ[i], totalZ) / totalZ) * len,
		                slotRight = (pick(relZ[i + goRight], totalZ) / totalZ) * len,
		                xInsideLinearSlot = x - linearSlotLeft,
		                ret;

		            // Set crosshairWidth for every point (#8173)
		            if (point) {
		                point.crosshairWidth = slotRight - slotLeft;
		            }

		            ret = slotLeft +
		            xInsideLinearSlot * (slotRight - slotLeft) /
		            (linearSlotRight - linearSlotLeft);

		            return ret;
		        },

		        // Extend translation by distoring X position based on Z.
		        translate: function () {

		            // Temporarily disable crisping when computing original shapeArgs
		            var crispOption = this.options.crisp,
		                xAxis = this.xAxis;

		            this.options.crisp = false;

		            seriesTypes.column.prototype.translate.call(this);

		            // Reset option
		            this.options.crisp = crispOption;

		            var inverted = this.chart.inverted,
		                crisp = this.borderWidth % 2 / 2;

		            // Distort the points to reflect z dimension
		            this.points.forEach(function (point, i) {
		                var left, right;

		                if (xAxis.variwide) {
		                    left = this.postTranslate(
		                        i,
		                        point.shapeArgs.x,
		                        point
		                    );

		                    right = this.postTranslate(
		                        i,
		                        point.shapeArgs.x + point.shapeArgs.width
		                    );

		                    // For linear or datetime axes, the variwide column should
		                    // start with X and extend Z units, without modifying the
		                    // axis.
		                } else {
		                    left = point.plotX;
		                    right = xAxis.translate(
		                        point.x + point.z,
		                        0,
		                        0,
		                        0,
		                        1
		                    );
		                }

		                if (this.options.crisp) {
		                    left = Math.round(left) - crisp;
		                    right = Math.round(right) - crisp;
		                }

		                point.shapeArgs.x = left;
		                point.shapeArgs.width = right - left;

		                // Crosshair position (#8083)
		                point.plotX = (left + right) / 2;

		                // Adjust the tooltip position
		                if (!inverted) {
		                    point.tooltipPos[0] =
		                    point.shapeArgs.x + point.shapeArgs.width / 2;
		                } else {
		                    point.tooltipPos[1] =
		                    xAxis.len - point.shapeArgs.x - point.shapeArgs.width / 2;
		                }
		            }, this);
		        }

		        // Point functions
		    }, {
		        isValid: function () {
		            return H.isNumber(this.y, true) && H.isNumber(this.z, true);
		        }
		    });

		H.Tick.prototype.postTranslate = function (xy, xOrY, index) {
		    var axis = this.axis,
		        pos = xy[xOrY] - axis.pos;

		    if (!axis.horiz) {
		        pos = axis.len - pos;
		    }
		    pos = axis.series[0].postTranslate(index, pos);

		    if (!axis.horiz) {
		        pos = axis.len - pos;
		    }
		    xy[xOrY] = axis.pos + pos;
		};

		// Same width as the category (#8083)
		addEvent(H.Axis, 'afterDrawCrosshair', function (e) {
		    if (this.variwide && this.cross) {
		        this.cross.attr('stroke-width', e.point && e.point.crosshairWidth);
		    }
		});

		// On a vertical axis, apply anti-collision logic to the labels.
		addEvent(H.Axis, 'afterRender', function () {
		    var axis = this;

		    if (!this.horiz && this.variwide) {
		        this.chart.labelCollectors.push(function () {
		            return axis.tickPositions.map(function (pos, i) {
		                var label = axis.ticks[pos].label;

		                label.labelrank = axis.zData[i];
		                return label;
		            });
		        });
		    }
		});

		addEvent(H.Tick, 'afterGetPosition', function (e) {
		    var axis = this.axis,
		        xOrY = axis.horiz ? 'x' : 'y';

		    if (axis.variwide) {
		        this[xOrY + 'Orig'] = e.pos[xOrY];
		        this.postTranslate(e.pos, xOrY, this.pos);
		    }
		});

		H.wrap(H.Tick.prototype, 'getLabelPosition', function (
		    proceed,
		    x,
		    y,
		    label,
		    horiz,
		    labelOptions,
		    tickmarkOffset,
		    index
		) {
		    var args = Array.prototype.slice.call(arguments, 1),
		        xy,
		        xOrY = horiz ? 'x' : 'y';

		    // Replace the x with the original x
		    if (this.axis.variwide && typeof this[xOrY + 'Orig'] === 'number') {
		        args[horiz ? 0 : 1] = this[xOrY + 'Orig'];
		    }

		    xy = proceed.apply(this, args);

		    // Post-translate
		    if (this.axis.variwide && this.axis.categories) {
		        this.postTranslate(xy, xOrY, index);
		    }
		    return xy;
		});


		/**
		 * A `variwide` series. If the [type](#series.variwide.type) option is not
		 * specified, it is inherited from [chart.type](#chart.type).
		 *
		 * @extends   series,plotOptions.variwide
		 * @product   highcharts
		 * @apioption series.variwide
		 */

		/**
		 * An array of data points for the series. For the `variwide` series type,
		 * points can be given in the following ways:
		 *
		 * 1. An array of arrays with 3 or 2 values. In this case, the values correspond
		 *    to `x,y,z`. If the first value is a string, it is applied as the name of
		 *    the point, and the `x` value is inferred. The `x` value can also be
		 *    omitted, in which case the inner arrays should be of length 2. Then the
		 *    `x` value is automatically calculated, either starting at 0 and
		 *    incremented by 1, or from `pointStart` and `pointInterval` given in the
		 *    series options.
		 *    ```js
		 *       data: [
		 *           [0, 1, 2],
		 *           [1, 5, 5],
		 *           [2, 0, 2]
		 *       ]
		 *    ```
		 *
		 * 2. An array of objects with named values. The following snippet shows only a
		 *    few settings, see the complete options set below. If the total number of
		 *    data points exceeds the series'
		 *    [turboThreshold](#series.variwide.turboThreshold), this option is not
		 *    available.
		 *    ```js
		 *       data: [{
		 *           x: 1,
		 *           y: 1,
		 *           z: 1,
		 *           name: "Point2",
		 *           color: "#00FF00"
		 *       }, {
		 *           x: 1,
		 *           y: 5,
		 *           z: 4,
		 *           name: "Point1",
		 *           color: "#FF00FF"
		 *       }]
		 *    ```
		 *
		 * @sample {highcharts} highcharts/series/data-array-of-arrays/
		 *         Arrays of numeric x and y
		 * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
		 *         Arrays of datetime x and y
		 * @sample {highcharts} highcharts/series/data-array-of-name-value/
		 *         Arrays of point.name and y
		 * @sample {highcharts} highcharts/series/data-array-of-objects/
		 *         Config objects
		 *
		 * @type      {Array<Array<(number|string),number>|Array<(number|string),number,number>|*>}
		 * @extends   series.line.data
		 * @excluding marker
		 * @product   highcharts
		 * @apioption series.variwide.data
		 */

		/**
		 * The relative width for each column. On a category axis, the widths are
		 * distributed so they sum up to the X axis length. On linear and datetime axes,
		 * the columns will be laid out from the X value and Z units along the axis.
		 *
		 * @type      {number}
		 * @product   highcharts
		 * @apioption series.variwide.data.z
		 */

	}(Highcharts));
	return (function () {


	}());
}));
